package cn.txun05.csmall.passport.service.impl;

import cn.txun05.csmall.commons.ex.ServiceException;
import cn.txun05.csmall.passport.mapper.AdminMapper;
import cn.txun05.csmall.passport.mapper.AdminRoleMapper;
import cn.txun05.csmall.passport.pojo.entity.Admin;
import cn.txun05.csmall.passport.pojo.entity.AdminRole;
import cn.txun05.csmall.passport.pojo.param.AdminAddNewParam;

import cn.txun05.csmall.passport.pojo.param.AdminLoginInfoParam;
import cn.txun05.csmall.passport.security.AdminDetails;
import cn.txun05.csmall.passport.service.IAdminService;
import cn.txun05.csmall.commons.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
//@Controller
public class AdminServiceImpl implements IAdminService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Value("${csmall.jwt.secretKey}")
    private String secretKey;
    @Value("${csmall.jwt.duration}")
    private Long duration;
    @Override
    public void addNew(AdminAddNewParam adminAddNewParam) {
        log.debug("开始处理【添加管理员】的业务，参数{}",adminAddNewParam);
        //检查管理员用户名是否被占用，如果被占用，抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",adminAddNewParam.getUsername());
        int countByUsername =  adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员用户名统计匹配的结果数量：{}",countByUsername);
        if(countByUsername>0){
            String message = "添加管理员失败，名字被占用";
            log.warn(message);
            throw  new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }

        // TODO 检查管理员手机号码被占用，如果被占用，抛出异常
        // TODO 检查管理员电子邮箱被占用，如果被占用，抛出异常

        //将管理员数据写入数据库中
        Admin admin  = new Admin();
        BeanUtils.copyProperties(adminAddNewParam,admin);
        admin.setGmtLastLogin(null);
        admin.setLoginCount(0);
        admin.setLastLoginIp(null);
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        int rows  = adminMapper.insert(admin);
        if(rows!=1){
            String message = "添加管理员失败,服务器再忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
        log.debug("将新的管理员数据插入到数据完成！");
        //16：15开始

        //将管理员与角色的关联数据写入到数据库中
        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRolesList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for(int i=0;i<adminRolesList.length;i++){
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRolesList[i]= adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRolesList);
        if(rows!=adminRolesList.length){
            String message = "添加管理员失败,服务器再忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
        log.debug("插入数据受影响的行数："+rows);
        log.debug("将新的管理员与角色的关联数据插入到数据完成！");


    }


    @Override
    public String login(AdminLoginInfoParam adminLoginInfoParam) {
        log.debug("开始处理【管理员登录】的业务,参数:{}",adminLoginInfoParam);
        //Authentication对象封装用户名和密码
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoParam.getUsername(),
                adminLoginInfoParam.getPassword()
        );
        //authenticate()方法的底层会自动调用loadUserByUsername()
        //执行认证，并获取认证结果authenticate(包含UserDetail对象)
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("验证登录完成!认证结果：{}",authenticateResult);

        //从认证的结果中获取UserDetail对象(封装了用户信息)
        Object princpal = authenticateResult.getPrincipal();
        AdminDetails adminDetails = (AdminDetails) princpal;
        //取出权限集合
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",adminDetails.getId());
        claims.put("username",adminDetails.getUsername());
        //将权限集合转为json字符串，再放在jwt的载荷数据中
        claims.put("authoritiesJsonString", JSON.toJSONString(authorities));

       // String secretKey = "q23adcw4ere56te45ye4gty54..wew";
        String jwt = Jwts.builder()
                //header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                //payload  载荷
                .setClaims(claims)
                //设置有效期,从生成jwt开始计算时间
                .setExpiration(new Date(System.currentTimeMillis()+duration*60*1000))
                //验证签名 varify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                //生产jwt
                .compact();
        log.debug("生成了此管理员信息对应的jwt:{}",jwt);
        return jwt;
        //=====使用JWT后本方法不再需要以下2行代码
        //获取SecurityContext上下文对象，将认证结果存入SecurityContext中
        //SecurityContext securityContext = SecurityContextHolder.getContext();
        //securityContext.setAuthentication(authenticateResult);
    }
}
